package com.clx.channelHandler.hander;

import com.clx.compress.CompressWrapper;
import com.clx.compress.Compressor;
import com.clx.compress.CompressorFactory;
import com.clx.enumeration.RequestType;
import com.clx.serialize.Serializer;
import com.clx.serialize.SerializerFactory;
import com.clx.transport.message.CrpcRequest;
import com.clx.transport.message.CrpcResponse;
import com.clx.transport.message.MessageFormatConstant;
import com.clx.transport.message.RequestPayload;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Date;

/**
 * 基于长度字段的帧解码器
 * */
@Slf4j
public class CrpcResponseDecoder extends LengthFieldBasedFrameDecoder {
    public CrpcResponseDecoder() {
        super(
                // 找到当前报文的总长度，截取报文，截取出来的报文我们可以去进行解析
                // 最大帧的长度，超过这个maxFrameLength值会直接丢弃
                MessageFormatConstant.MAX_FRAME_LENGTH,
                // 长度字段的偏移量
                MessageFormatConstant.MAGIC.length + MessageFormatConstant.VERSION_LENGHT + MessageFormatConstant.HEADER_FIELD_LENGTH,
                // 长度字段的长度
                MessageFormatConstant.FULL_FIELD_LENGTH,
                // todo 负载的适配长度
                -(MessageFormatConstant.MAGIC.length + MessageFormatConstant.VERSION_LENGHT + MessageFormatConstant.HEADER_FIELD_LENGTH + MessageFormatConstant.FULL_FIELD_LENGTH),
                0);
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        Object decode = super.decode(ctx, in);
        if (decode instanceof ByteBuf){
            ByteBuf byteBuf = (ByteBuf) decode;
            return decodeFrame(byteBuf);
        }
        return null;
    }

    private Object decodeFrame(ByteBuf byteBuf) {
        // 1，解析魔数值
        byte[] magic = new byte[MessageFormatConstant.MAGIC.length];
        byteBuf.readBytes(magic);
        // 检测魔数是否匹配
        for (int i = 0; i < magic.length; i++) {
            if (magic[i] != MessageFormatConstant.MAGIC[i]){
                throw new RuntimeException("获得的请求类型不合法。");
            }
        }
        // 2.解析版本号
        byte version = byteBuf.readByte();
        if (version > MessageFormatConstant.VERSION){
            throw new RuntimeException("获取的版本请求不被支持。");
        }

        // 3,解析头部的长度
        short headLength = byteBuf.readShort();

        // 4.解析总长度
        int fullLength = byteBuf.readInt();

        // 5，请求类型,
        byte responseCode = byteBuf.readByte();
        // 6，序列化类型
        byte serializeTypeType = byteBuf.readByte();
        // 7，压缩类型
        byte compressType = byteBuf.readByte();
        // 8，请求id
        long requestId = byteBuf.readLong();
        // 9，时间戳
        long timeStamp = byteBuf.readLong();

        //我们需要封装
        CrpcResponse crpcResponse = new CrpcResponse();
        crpcResponse.setCode(responseCode);
        crpcResponse.setCompressType(compressType);
        crpcResponse.setSerializeType(serializeTypeType);
        crpcResponse.setRequestId(requestId);
        crpcResponse.setTimeStamp(timeStamp);


        // todo 心跳请求没有负载，此处可以判断并直接返回
//        if (requestType == RequestType.HEART_BEAT.getId()){
//            return crpcRequest;
//        }

        int bodyLength = fullLength - headLength;
        byte[] payload = new byte[bodyLength];
        byteBuf.readBytes(payload);

        if (payload.length > 0) {
            // 有了字节数组之后就可以减压缩反序列化
            // 1,解压缩
            Compressor compressor = CompressorFactory.getCompressor(compressType).getCompressor();
            payload = compressor.decompress(payload);

            // 2 反序列化
            Serializer serializer = SerializerFactory.getSerialze(crpcResponse.getSerializeType()).getSerializer();
            Object body = serializer.deserialize(payload, Object.class);
            crpcResponse.setBody(body);
        }

        if (log.isDebugEnabled()){
            log.debug("响应【{}】已经在调用端完成解码工作。",crpcResponse.getRequestId());
        }
        return crpcResponse;
    }
}
